package com.borya.filter;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.borya.constant.SystemConstant;
import com.borya.filter.auth.AppType;
import com.borya.filter.auth.AuthHelper;
import com.borya.filter.auth.AuthRequest;
import com.borya.filter.auth.AuthResponse;
import com.borya.framework.annotation.Filter;
import com.borya.framework.core.ServerFilter;
import com.borya.framework.core.ServerRequest;
import com.borya.framework.core.ServerResponse;
import com.borya.model.db.User;
import com.borya.model.entity.HeaderEntity;
import com.borya.model.entity.UserToken;
import com.borya.statuscode.StatusCode;
import com.borya.userauth.UserAuthManager;
import com.borya.util.Constant;
import com.borya.util.filter.FilterUtil;

import io.netty.util.CharsetUtil;

@Filter
public class MobileFilter implements ServerFilter {

	private Logger log = Logger.getLogger(getClass());

	@Override
	public boolean doFilter(ServerRequest request, ServerResponse response) {
		final String host = request.ip();
		final String url = request.path();

		Predicate<String> pre2 = str -> !str.contains("/c/");
		if (pre2.test(url)) {
			return false;
		}
		final String boryaAuth = request.headers().get("boryaAuth");
		List<String> authParams = Arrays.stream(boryaAuth.split(",")).collect(Collectors.toList());
		/** 单点结算，拦截请求，转发至权限校验接口开始 **/
		if (Objects.equals(authParams.get(4), AppType.DEVICE_SDK.getType())) {
			// 走单点结算的拦截器
			return FilterUtil.filterSdkApp(request, response);
		}

		boolean uploadImgFile = false;
		if (url.contains("c/uploadImgFile")) {
			uploadImgFile = true;
		}
		String body = null;
		if (!uploadImgFile) {
			// 请求体
			body = request.text();
		} else {
			// 文件流上传，曾经请求体里的body放到了hearder的authrizatuon中
			body = request.headers().get("Authorization");
		}
		// final String body = request.text();
		if (StringUtils.isBlank(body)) {
			log.warn("[" + host + "] Server recv msg is empty,url=" + url);
			response.content().writeBytes(StatusCode.PARAM_ERROR.toJSON("参数不能为空！").getBytes(CharsetUtil.UTF_8));
			return true;
		}
		if (authParams.size() < 5) {
			log.warn("[" + host + "] Server recv error,url=" + url + ",boryaAuth=" + boryaAuth);
			// response.content().writeBytes(StatusCode.FORBID.toJSON().getBytes(CharsetUtil.UTF_8));
			return true;
		}

		// 校验sign和版本
		AuthHelper authHelper = new AuthHelper();
		AuthRequest authRequest = authHelper.getAuthRequest(url, host, body, authParams);
		AuthResponse authResponse = AuthHelper.auth(authRequest);
		if (!authResponse.getAccess()) {
			response.content().writeBytes(authResponse.getMsg().getBytes(CharsetUtil.UTF_8));
			return true;
		}
		JSONObject json = authResponse.getJson();
		// 校验token信息
		if (Objects.isNull(json)) {
			log.warn("[" + host + "] Parse json error,url=" + url);
			return true;
		}
		HeaderEntity authHeader = authHelper.getHeaderEntity(authParams);
		final String packageName = AuthHelper.getPackageName(authHeader.getAppType(), json.getString("packageName"));
		if (StringUtils.isEmpty(packageName)) {
			log.warn("未查找到包名");
			return true;
		}
		String decryptToken = "";
		try {
			final String token = json.getString("token");
			final String applicationId = json.getString("applicationID");
			final long timestamp = json.getLong("timestamp");
			final String userId = json.getString("userId");
			// json.containsKey("userId")?json.getString("userId"):"";
			// 登录之前没有userid
			if (StringUtils.isBlank(token) || StringUtils.isBlank(applicationId)) {
				log.warn("[" + host + "] Param error,url=" + url);
				return true;
			}
			// key特殊处理
			// final String key = userId.trim().length() == 0 ?
			// json.getString("phone") : userId;
			decryptToken = authHelper.getDecryptToken(authHeader, token, timestamp, userId, packageName);
			if (StringUtils.isBlank(decryptToken)) {
				log.warn("[" + host + "] Token error,token=[" + decryptToken + "],url=" + url + ",boryaAuth="
						+ boryaAuth);
				response.content().writeBytes(StatusCode.FORBID.toJSON("Token错误").getBytes(CharsetUtil.UTF_8));
				return true;
			}
			final String[] tokens = decryptToken.split(",", -1);
			if (tokens.length < 6) {
				log.warn("[" + host + "] Token解析错误,token=[" + token + "],url=" + url + ",boryaAuth=" + boryaAuth);
				response.content().writeBytes(StatusCode.FORBID.toJSON("").getBytes(CharsetUtil.UTF_8));
				return true;
			}

			UserToken ut = authHelper.getUserToken(url, host, tokens);
			// 校验crc32
			if (Constant.PROD_ENV) {
				authHelper.checkCrc32(url, authHeader, token, ut);
			}
			authHelper.checkHookFlag(authRequest, ut);
			authHelper.checkSdkInfo(authRequest, ut, json, packageName);
			boolean tokenParams = Stream.of(ut.getAppVersion(), ut.getOsVersion(), ut.getOsType(), ut.getPhoneType(),
					ut.getNet(), ut.getTmsi()).anyMatch(StringUtils::isEmpty);
			if (tokenParams) {
				log.warn("[" + host + "] Params error,url=" + url + ",boryaAuth=" + boryaAuth);
				response.content().writeBytes(StatusCode.FORBID.toJSON("请求参数错误").getBytes(CharsetUtil.UTF_8));
				return true;
			}

			json.put("appVersion", ut.getAppVersion());
			json.put("osVersion", ut.getOsVersion());
			json.put("osType", ut.getOsType());
			json.put("phoneType", ut.getPhoneType());
			json.put("net", ut.getNet());
			json.put("longitude", ut.getLongitude());
			json.put("latitude", ut.getLatitude());
			json.put("host_ip", host);
			json.put("packageName", packageName);
			json.put("imei", ut.getImei());
			json.put("appType", authHeader.getAppType());
			json.put("boryaAuth", JSONObject.toJSONString(authHeader));
			// json.put("backgroundVersion",
			// getBackgroundVersion(authHeader.getAppType(), ut.getOsType()));
			// 获取短信验证码/登录接口直接放过 //商户自注册相关接口直接放过
			if (url.endsWith("/c/user/login") || url.endsWith("/c/user/getSmsCode") || url.endsWith("/c/user/getCode")
					|| url.endsWith("/c/user/createVisitor")) {
				request.setAttribute("json", json);
				return false;
			}
			if (url.endsWith(SystemConstant.Sdk.API_CHECK) || url.endsWith(SystemConstant.Sdk.API_LOGIN)
					|| url.endsWith(SystemConstant.Sdk.API_LOGIN_CODE)
					|| url.endsWith(SystemConstant.Sdk.API_UPLOAD_REGISTER_IMAGE)
					|| url.endsWith(SystemConstant.Sdk.API_REGISTER)) {
				json.put("tmsi", ut.getTmsi());
				request.setAttribute("json", json);
				return false;
			}
			Map<String, String> map = new HashMap<String, String>();
			map.put("userId", userId);
			map.put("url", url);
			map.put("host", host);
			map.put("tmsi", ut.getTmsi());
			map.put("appVersion", ut.getAppVersion());
			map.put("osVersion", ut.getOsVersion());
			map.put("packageName", packageName);
			map.put("osType", ut.getOsType());
			map.put("phoneType", ut.getPhoneType());
			map.put("net", ut.getNet());
			map.put("applicationId", applicationId);
			map.put("longitude", ut.getLongitude());
			map.put("latitude", ut.getLatitude());
			map.put("imei", ut.getImei());
			map.put("locationFlag", ut.getLocationFlag());
			request.setAttribute("json", json);
			return process(request, response, map, authHeader);
		} catch (Exception e) {
			log.error(e.getMessage() + "url=" + url + ",boryaAuth=" + boryaAuth + ",token=" + decryptToken, e);
			response.content().writeBytes(StatusCode.FORBID.toJSON("请求参数错误").getBytes(CharsetUtil.UTF_8));
			return true;
		}
	}

	private boolean process(ServerRequest request, ServerResponse response, Map<String, String> map,
			HeaderEntity authHeader) {
		// return User/String
		Object tmp = UserAuthManager.getInstance().doPrepare(map, authHeader);
		if (tmp == null) {
			response.content().writeBytes(StatusCode.PARAM_ERROR.toJSON().getBytes(CharsetUtil.UTF_8));
			return true;
		}
		if (tmp instanceof String) {
			response.content().writeBytes(((String) tmp).getBytes(CharsetUtil.UTF_8));
			return true;
		}

		if (tmp instanceof User) {
			request.setAttribute("user", (User) tmp);
			return false;
		}

		return false;
	}
}